home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
dskut
/
dlcpmv23.zip
/
CPMV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-29
|
20KB
|
721 lines
/*************************************************************************
* DL_CPMV v2.2 92/02/15 by Dennis Lo
* This program and its source code are in the public domain.
*
* DESCRIPTION:
* DL_CPMV is a BSD Unix-like cp and mv for MS-DOS. Unlike most
* other MS-DOS cp and mv programs, this one:
* - has the -p and -v options from BSD/SunOS.
* - can move files across drives.
* - can rename directories as well as files
* - supports environment variable references in file names
* - allows forward slashes to be used in path names
*
* TO COMPILE:
* The same source file contains both MV and CP. To compile, #define
* either CP or MV below, rename this file to cp.c or mv.c, and compile
* with Turbo C++ v1.01, small memory model:
* eg. tcc cp.c or
* tcc mv.c
* Other versions of Turbo C should also work but have not been tested.
* User documentation is embedded in HelpExit().
* Notes: a "filename" means something like "c:/etc/zansi.sys". A
* "filespec" means something like "c:/etc/*.sys".
*
* TEST SUITE:
* - mv/cp within current dir: mv mv.obj mv.2
* - mv/cp from current dir to other dir: mv mv.obj ..
* - mv/cp from other dir to another dir: mv c:/d/work/mv.obj /tmp/mv.o
* - mv/cp across drives: mv mv.obj e:
* - mv/cp across drives with paths: mv c:/d/work/mv.obj e:/tmp
* - test -f/-i flags cp -p cp.obj mv.obj
* - test -p/-n flags: mv -p mv.obj a:
* - test -v/-q flags: mv -q mv.obj mv.2
* - test several flags together: mv -ipn mv.obj mv.2
* - test flags in env variable: set MV=piv
* - mv/cp -r across drives mv -r c:/tmp/1 e:/
* - mv/cp -r on same drive mv -r /tmp/1/*.* /tmp/2
* - mv/cp no -r: subdirs not moved mv *.* ..
*
* CHANGE LOG:
* Version 2.3 92/03/30:
* - return error code of 0 when successful
* Version 2.2 92/01/08:
* - fixed cp -r bug that tries to remove subdirectories
* Version 2.1 92/01/01:
* - added -r option
* - added explicit wildcard expansion to allow cases like $junk/*.*
* Version 2.0 91/12/28:
* - switched from Datalight C to Turbo C++ (and the .exe grew by 5K !)
* - mv defaults to -p instead of -n
* - mv can rename directories now
* Version 1.6 91/01/20:
* - allow moving across drives
* TODO:
* - Switch disks if src<>dst drive, and dest drive is a floppy, and
* dest free space < current file size
* - package for release
*************************************************************************/
/*
* Define one of the following to indicate whether this is 'mv' or 'cp'
*/
#define CP
/*
#define MV
*/
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dos.h>
#include <dir.h>
#include <conio.h>
#include <stdlib.h>
/*=====================================================================
* Macros
*=====================================================================
*/
/* Macro to write a string to stdout (avoids the need to use printf) */
#define PUT(str) fputs (str, stdout)
/*=====================================================================
* Global Variables
*=====================================================================
*/
int Force_flag = 1;
int Verbose_flag = 0;
int Recursive_flag = 0;
#ifdef CP
int Preserve_flag = 0; /* CP: use new timestamp by default */
#else
int Preserve_flag = 1; /* MV: preserve timestamp by default */
#endif
/*=====================================================================
* Print a help message and exit
*=====================================================================
*/
void
HelpExit ()
{
#ifdef CP
PUT ("DL_CP - a BSD Unix style file copy utility v2.3 92/03/30 Dennis Lo\n");
PUT ("USAGE: cp [-fipnvq] file dest_file\n");
PUT (" or: cp [-fipnvq] file1 [file2...fileN] dest_directory\n");
PUT (" -f = Force overwrites without prompting (default).\n");
PUT (" -i = Interactively prompt before overwriting (opposite of -f).\n");
PUT (" -p = Preserve original timestamp when copying.\n");
PUT (" -n = use New timestamp when copying (opposite of -p). (default)\n");
PUT (" -v = Verbose - show each file copied.\n");
PUT (" -q = Quiet - opposite of -v (default).\n");
PUT (" -r = Recursively descend & copy sub-directories.\n");
PUT ("Default arguments can be put in the CP environment variable. (eg. 'set CP=ipv')\n");
PUT ("File names can contain environment variable references (eg. 'cp $work/*.c a:')\n");
#else
PUT ("DL_MV - a BSD Unix style file move utility v2.3 92/03/30 Dennis Lo\n");
PUT ("USAGE: mv [-fipnvq] old_file new_file\n");
PUT (" or: mv [-fipnvq] file1 [file2...fileN] dest_directory\n");
PUT (" -f = Force overwrites without prompting (default).\n");
PUT (" -i = Interactively prompt before overwriting (opposite of -f).\n");
PUT (" -p = Preserve original timestamp when copying. (default)\n");
PUT (" -n = use New timestamp when copying (opposite of -p).\n");
PUT (" -v = Verbose - show each file copied.\n");
PUT (" -q = Quiet - opposite of -v (default).\n");
PUT (" -r = Recursively descend & move sub-directories.\n");
PUT ("Can move directories. Can move files from one drive to another.\n");
PUT ("Default arguments can be put in the MV environment variable. (eg. 'set MV=ipv')\n");
PUT ("File names can contain environment variable references (eg. 'mv $work/*.c a:')\n");
#endif
exit (1);
}
/*=====================================================================
* Return TRUE if a filespec is a file
*=====================================================================
*/
IsFile (filespec)
char *filespec;
{
struct ffblk findblk;
return (findfirst (filespec, &findblk, 0) == 0);
/* maybe should change the 0 to FA_HIDDEN|FA_SYSTEM */
}
/*=====================================================================
* Return TRUE if a filespec is a directory
*=====================================================================
*/
IsDir (filespec)
char *filespec;
{
struct ffblk findblk;
int lastchar = filespec [strlen (filespec) - 1];
return ((findfirst (filespec, &findblk, FA_DIREC) == 0
&& !IsFile (filespec))
|| lastchar == '.' || lastchar == '/' || lastchar == '\\');
}
/*=====================================================================
* Interpret an arguments string of the form "fiv" (not "-f -iv")
*=====================================================================
*/
void
ParseArgs (str)
char *str;
{
char *param;
static char errmsg[] = "-?\n";
for (param = str; *param; param++)
{
switch (*param)
{
case 'f': /* Force overwrites */
Force_flag = 1;
break;
case 'i': /* Interactive */
Force_flag = 0;
break;
case 'n': /* cp: create New file */
Preserve_flag = 0;
break;
case 'p': /* cp: Preserve timestamp & modes */
Preserve_flag = 1;
break;
case 'q': /* Quiet */
Verbose_flag = 0;
break;
case 'r': /* Recursive */
Recursive_flag = FA_DIREC;
break;
case 'v': /* Verbose */
Verbose_flag = 1;
break;
default:
errmsg[1] = *param;
PUT ("Invalid parameter "); PUT (errmsg);
HelpExit ();
}
}
}
/*=====================================================================
* Return the drive letter of a filename
*=====================================================================
*/
char
DriveName (filename)
char *filename;
{
char drive;
/*
* If the drive name is embedded in the given file name then
* extract it
*/
if (filename[1] == ':')
{
drive = filename[0];
}
/* else return current drive */
else
{
char path [80];
getcwd (path, 79);
drive = *path;
}
return (toupper (drive));
}
/*=====================================================================
* Return a pointer to the filename portion of a filespec.
* (Skips the drive specifier and the path)
*=================================